﻿using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    /// <summary>
    /// .NET 2.0 异步编程模型——基于事件的异步模式，即EAP（Event-based Asynchronous Pattern）
    /// </summary>
    public partial class Form_Async_EAP : Form
    {
        public int DownloadSize = 0;
        public string downloadPath = null;
        long totalSize = 0;
        const int BufferSize = 2048;
        byte[] BufferRead = new byte[BufferSize];
        FileStream filestream = null;
        HttpWebResponse myWebResponse = null;

        public Form_Async_EAP()
        {
            InitializeComponent();
            txbUrl.Text = "http://k3.chunk.cn:8053/POSReport20/File/%E5%8D%9520240101_1217_1218171322608.xlsx";

            btnPause.Enabled = false;

            GetTotalSize();

            downloadPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + Path.GetFileName(this.txbUrl.Text.Trim());
            if (File.Exists(downloadPath))
            {
                FileInfo fileInfo = new FileInfo(downloadPath);
                DownloadSize = (int)fileInfo.Length;
                progressBar1.Value = (int)((float)DownloadSize / (float)totalSize * 100);
            }

            // 使BackgroundWorker类支持ReportProgress和SupportsCancellation操作
            bgWorkerFileDownload.WorkerReportsProgress = true;          // 报告进度更新
            bgWorkerFileDownload.WorkerSupportsCancellation = true;         // 异步取消操作

        }

        private void btnDownLoad_Click(object sender, EventArgs e)
        {
            if (bgWorkerFileDownload.IsBusy != true)    // 是否正在运行异步操作
            {
                bgWorkerFileDownload.RunWorkerAsync();      // 开始执行后台操作

                filestream = new FileStream(downloadPath, FileMode.OpenOrCreate);

                filestream.Seek(DownloadSize, SeekOrigin.Begin);

                btnDownLoad.Enabled = false;
                btnPause.Enabled = true;
            }
            else
            {
                MessageBox.Show("正在执行操作，请稍后");
            }
        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            if (bgWorkerFileDownload.IsBusy && bgWorkerFileDownload.WorkerSupportsCancellation == true)
            {
                bgWorkerFileDownload.CancelAsync();         // 取消下载操作
            }
        }

        private void GetTotalSize() // 获得文件总大小
        {
            HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(txbUrl.Text.Trim());
            HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();
            totalSize = response.ContentLength;
            response.Close();
        }

        private void bgWorkerFileDownload_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bgworker = sender as BackgroundWorker;

            // Do the DownLoad operation
            // Initialize an HttpWebRequest object
            HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(txbUrl.Text.Trim());

            // If the part of the file have been downloaded,
            // The server should start sending data from the DownloadSize to the end of the data in the HTTP entity.
            if (DownloadSize != 0)
            {
                myHttpWebRequest.AddRange(DownloadSize);
            }

            // assign HttpWebRequest instance to its request field.
            myWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
            Stream responseStream = myWebResponse.GetResponseStream();
            int readSize = 0;

            while (true)
            {
                if (bgworker.CancellationPending == true)  // 应用程序是否已取消后台操作
                {
                    e.Cancel = true;
                    break;
                }

                readSize = responseStream.Read(BufferRead, 0, BufferRead.Length);
                if (readSize > 0)
                {
                    DownloadSize += readSize;
                    int percentComplete = (int)((float)DownloadSize / (float)totalSize * 100);      // 计算比例
                    filestream.Write(BufferRead, 0, readSize);

                    // 报告进度，引发ProgressChanged事件的发生
                    bgworker.ReportProgress(percentComplete);
                }
                else
                {
                    break;
                }
            }


        }

        private void bgWorkerFileDownload_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

        // RunWorkerCompleted 当异步操作已完成、被取消或引发异常时被触发。
        private void bgWorkerFileDownload_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
                myWebResponse.Close();
            }
            else if (e.Cancelled)
            {
                MessageBox.Show(String.Format("下载暂停，下载的文件地址为：{0}\n 已经下载的字节数为: {1}字节", downloadPath, DownloadSize));
                myWebResponse.Close();
                filestream.Close();

                this.btnDownLoad.Enabled = true;
                this.btnPause.Enabled = false;
            }
            else
            {
                MessageBox.Show(String.Format("下载已完成，下载的文件地址为：{0}，文件的总字节数为: {1}字节", downloadPath, totalSize));

                this.btnDownLoad.Enabled = false;
                this.btnPause.Enabled = false;
                myWebResponse.Close();
                filestream.Close();
            }
        }

        // 以上代码首先在下载按钮的处理函数中，调用了BackgroundWorker对象的RunWorkerAsync方法，然后触发了DoWork事件。
        // DoWork事件的处理函数中，执行了文件下载操作，并调用了BackgroundWorker对象的ReportProgress方法，触发了ProgressChanged事件。
        // 接着在ProgressChanged事件的处理函数中完成了进度报告的操作，并在暂停按钮的处理函数中调用CancelAsync方法来取消下载操作，从而触发了RunWorkerCompleted事件。
        // 在RunWorkerCompleted事件的处理函数中，程序则实现了弹窗，显示了已经下载的字节数，并更新了下载按钮和暂停按钮的状态。

        // 这段代码除了支持暂停下载和下载进度报告两个功能外，还实现了断点续传功能。
    }
}
